import { CSSProperties, memo, useEffect, useMemo, useRef, useState } from "react";
import { Drawer } from "antd";
import type { DrawerInstance, DrawerProps } from "./typing";
import DrawerFooter from "./components/DrawerFooter";
import DrawerHeader from "./components/DrawerHeader";
import { DrawerPropsType, DrawerPropsDefault } from "./props";
import { isFunction, isNumber } from "@/utils/is";
import { deepMerge } from "@/utils";
import { childrenToMap } from "@/utils/helper/tsxHelper";
// import { ScrollContainer } from "@/components/Container";

interface ComponentProps extends ComponentNode {
	// emit Function
	register?: Function;
	close?: Function;
	ok?: Function;
}

const BasicDrawer = (props: DrawerPropsType & ComponentProps) => {
	// fix React18 "defaultProps" problem
	props = Object.assign({}, { ...DrawerPropsDefault, ...props });

	const attrs = {};
	const slots: Recordable<React.ReactNode> = childrenToMap(props.children);
	const [propsRef, setPropsRef] = useState<Partial<DrawerProps | null>>(null);
	const [openRef, setOpenRef] = useState(false);
	const uid = useRef(0);

	const prefixCls = "jok-basic-drawer";
	const prefixVar = "jok";

	const drawerInstance: DrawerInstance = {
		setDrawerProps: setDrawerProps as any,
		emitOpen: undefined
	};

	const getMergeProps: any = useMemo((): DrawerProps => {
		return deepMerge(props, propsRef) as any;
	}, [propsRef]);

	const getProps = useMemo((): DrawerProps => {
		const opt = {
			placement: "right",
			...attrs,
			...getMergeProps,
			open: openRef
		};
		opt.title = undefined;
		const { isDetail, width, wrapClassName, getContainer } = opt;
		if (isDetail) {
			if (!width) opt.width = "100%";

			const detailCls = `${prefixCls}__detail`;
			opt.rootClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;

			if (!getContainer) opt.getContainer = `.${prefixVar}-layout-content`;
		}
		return opt as DrawerProps;
	}, [getMergeProps, openRef]);

	const getBindValues = useMemo((): DrawerProps => {
		return {
			...attrs,
			...getProps
		};
	}, [getProps]);

	// Custom implementation of the bottom button,
	const getFooterHeight = useMemo(() => {
		const { footerHeight, showFooter } = getProps;
		if (showFooter && footerHeight) {
			return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace("px", "")}px`;
		}
		return `0px`;
	}, [getProps.footerHeight, getProps.showFooter]);

	const getScrollContentStyle = useMemo((): CSSProperties => {
		return {
			position: "relative",
			// height: `calc(100% - ${getFooterHeight})`
			paddingBottom: `calc(60px - 24px)`
		};
	}, [getFooterHeight]);

	// const getLoading = useMemo(() => {
	// 	return !!getProps?.loading;
	// }, [getProps?.loading]);

	// Cancel event
	async function onClose() {
		const { closeFunc } = getProps;
		props.close && props.close();
		if (closeFunc && isFunction(closeFunc)) {
			const res = await closeFunc();
			setOpenRef(!res);
			return;
		}
		setOpenRef(false);
	}

	function setDrawerProps(props: Partial<DrawerProps>): void {
		// Keep the last setDrawerProps
		setPropsRef(deepMerge(propsRef || ({} as any), props));
		if (Reflect.has(props, "open")) setOpenRef(!!props.open);
	}

	function handleOk() {
		props.ok && props.ok();
	}

	/** Effect */

	useEffect(() => {
		uid.current = parseInt(Math.random() * 10000);
		props.register && props.register(drawerInstance, uid.current);
		return () => {
			// component beforeDestroy clear function
			setPropsRef(null);
			setOpenRef(false);
			uid.current = 0;
			drawerInstance.emitOpen = undefined;
		};
	}, []);

	useEffect(() => {
		if (props.open !== openRef) setOpenRef(!!props.open);
	}, [props.open]);

	useEffect(() => {
		drawerInstance.emitOpen?.(openRef, uid.current);
	}, [openRef]);

	/** Render */

	const renderTitle = () => {
		return slots?.title ? (
			slots.title
		) : (
			<DrawerHeader
				title={getMergeProps.title}
				isDetail={props.isDetail}
				showDetailBack={props.showDetailBack}
				close={onClose}
			></DrawerHeader>
		);
	};

	return (
		<Drawer {...getBindValues} className={prefixCls} onClose={onClose} title={renderTitle()}>
			{/* <ScrollContainer loading={getLoading} style={getScrollContentStyle} loadingTip={props.loadingText}> */}
			<div style={getScrollContentStyle}>{slots.default}</div>
			{/* </ScrollContainer> */}
			<DrawerFooter {...getProps} height={getFooterHeight} close={onClose} ok={handleOk} slots={slots}></DrawerFooter>
		</Drawer>
	);
};

export default memo(BasicDrawer);
